/******************************************************************************\
    MessageDataBase.h discribes a database of messages.
    It's used with acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once

#include ".\BaseDataBase.hpp"

namespace nsMessageDataBase
{
	const unsigned long CONTESTANT_JURY = 0xfffffffful;
	const unsigned long CONTESTANT_ALL = 0xfffffffeul;

	const unsigned long CONTEST_UNDEFINED = 0xfffffffful;

	struct sMessageData
	{
		unsigned long Key;
		unsigned long ContestId;
		unsigned long SourceContestantId;
		unsigned long DestinationContestantId;
		bool IsRead;
		unsigned long long Time;
		unsigned long Message;
		unsigned long MessageSize;
	};

	struct DestinationContestantIdCompare : public std::binary_function< cDataPointer< sMessageData >, cDataPointer< sMessageData >, bool >
	{
		bool operator()( const cDataPointer< sMessageData > &left, const cDataPointer< sMessageData > &right )
		{
			return left->DestinationContestantId < right->DestinationContestantId ||
				left->DestinationContestantId == right->DestinationContestantId && 
				( left->ContestId < right->ContestId ||
				  left->ContestId == right->ContestId && 
				  ( left->IsRead < right->IsRead ||
				    left->IsRead == right->IsRead && 
					 ( left->Time < right->Time ||
					   left->Time == right->Time && left->Key < right->Key ) ) );
		}
	};

	typedef cBaseDataBase< sMessageData >::KeyIterator KeyIterator;
	typedef cPublicIterator< sMessageData, DestinationContestantIdCompare > DestinationContestantIdIterator;

	class cWardMessageDataBase : public cBaseDataBase< sMessageData >
	{
	private:
		std::set< cDataPointer< sMessageData >, DestinationContestantIdCompare > DestinationContestantIdIndex;
	protected:
		virtual bool Indexed( const cDataPointer< sMessageData > &data_pointer )
		{
			//return DestinationContestantIdIndex.find( data_pointer ) != DestinationContestantIdIndex.end();
			return false;
		}
		virtual void InsertIndex( const cDataPointer< sMessageData > &data_pointer )
		{
			DestinationContestantIdIndex.insert( data_pointer );
		}
		virtual void UpdateIndex( const cDataPointer< sMessageData > &data_pointer, unsigned long index )
		{
			DestinationContestantIdIndex.find( data_pointer )->Index = index;
		}
		virtual void DeleteIndex( const cDataPointer< sMessageData > &data_pointer )
		{
			DestinationContestantIdIndex.erase( data_pointer );
		}
		virtual void ClearIndex()
		{
			DestinationContestantIdIndex.clear();
		}
	public:
		cWardMessageDataBase( bool auto_update )
			: cBaseDataBase( auto_update )
		{
		}
		DestinationContestantIdIterator BeginByDestinationContestantId() const
		{
			return DestinationContestantIdIterator( DestinationContestantIdIndex.begin() );
		}
		DestinationContestantIdIterator LowerBoundByDestinationContestantId( unsigned long destination_contestant_id, unsigned long contest_id ) const
		{
			sMessageData message_data;
			message_data.DestinationContestantId = destination_contestant_id;
			message_data.ContestId = contest_id;
			message_data.IsRead = false;
			message_data.Time = 0;
			message_data.Key = 0;
			return DestinationContestantIdIterator( DestinationContestantIdIndex.lower_bound( cDataPointer< sMessageData >( &message_data ) ) );
		}
		DestinationContestantIdIterator UpperBoundByDestinationContestantId( unsigned long destination_contestant_id, unsigned long contest_id ) const
		{
			sMessageData message_data;
			message_data.DestinationContestantId = destination_contestant_id;
			message_data.ContestId = contest_id;
			message_data.IsRead = true;
			message_data.Time = ~0uI64; // 
			message_data.Key = 0xfffffffful;
			return DestinationContestantIdIterator( DestinationContestantIdIndex.upper_bound( cDataPointer< sMessageData >( &message_data ) ) );
		}
		DestinationContestantIdIterator EndByDestinationContestantId() const
		{
			return DestinationContestantIdIterator( DestinationContestantIdIndex.end() );
		}
	};

	class cMessageDataBase : public cPointerObject< cWardMessageDataBase >
	{
	public:
		bool Create( bool auto_update = false )
		{
			cWardMessageDataBase *ward_message_data_base;
			try
			{
				ward_message_data_base = new cWardMessageDataBase( auto_update );
			}
			catch( ... )
			{
				return false;
			}
			if( !SwitchToWardObject( ward_message_data_base ) )
			{
				delete ward_message_data_base;
				return false;
			}
			return true;
		}
		void Destroy()
		{
			SwitchToSubObject( NULL );
		}
	};
}
